package cn.lingyangwl.agile.misc.short_link.service.impl;

import cn.lingyangwl.agile.infra.*;
import cn.lingyangwl.agile.infra.module.group.model.rqrs.*;
import cn.lingyangwl.agile.infra.module.misc.*;
import cn.lingyangwl.agile.misc.short_link.assembly.*;
import cn.lingyangwl.agile.misc.short_link.manager.*;
import cn.lingyangwl.agile.misc.short_link.mapper.*;
import cn.lingyangwl.agile.misc.short_link.model.entity.*;
import cn.lingyangwl.agile.misc.short_link.model.rqrs.*;
import cn.lingyangwl.agile.misc.short_link.service.*;
import cn.lingyangwl.agile.model.enums.*;
import cn.lingyangwl.framework.mybatis.plus.utils.*;
import cn.lingyangwl.framework.tool.core.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 短链访问日志
 *
 * @author shenguangyang
 */
@Slf4j
@Service
public class AccessLogServiceImpl extends ServiceImpl<SlAccessLogMapper, AccessLog>
    implements IService<AccessLog>, AccessLogService {
    @Resource
    private InfraApi infraApi;
    @Resource
    private AccessLogAssembly accessLogAssembly;
    @Resource
    private SlLinkDomainManager linkDomainManager;
    @Resource
    private ShortLinkService shortLinkService;

    /**
     * 分页查询 短链访问日志
     *
     * @return 返回分页数据
     */
    @Override
    public IPage<AccessLogResp> pageAccessLog(AccessLogPageReq req) {
        LocalDateTime beginTime = req.getBeginLocalDateTime();
        LocalDateTime endTime = req.getEndLocalDateTime();
        LambdaQueryWrapper<AccessLog> queryWrapper = AccessLog.lqw()
            .eq(StringUtils.isNotEmpty(req.getCode()), AccessLog::getCode, req.getCode())
            .eq(Objects.nonNull(req.getGroupId()), AccessLog::getGroupId, req.getGroupId())
            .ge(Objects.nonNull(beginTime), AccessLog::getCreatedAt, beginTime)
            .le(Objects.nonNull(endTime), AccessLog::getCreatedAt, endTime)
            .orderByDesc(AccessLog::getCreatedAt);

        IPage<AccessLog> pageData = this.page(PageUtil.to(req), queryWrapper);
        List<Long> groupIds = pageData.getRecords().stream().map(AccessLog::getGroupId).distinct().collect(Collectors.toList());
        groupIds.add(-1L);

        Set<Long> domainIds = pageData.getRecords().stream().map(AccessLog::getDomainId).collect(Collectors.toSet());
        domainIds.add(-1L);

        DataGroupQuery groupQuery = new DataGroupQuery().setIds(groupIds).setBizType(DataGroupBizTypeEnum.SHORT_LINK.getType());
        Map<Long, DataGroupDto> groupMap = infraApi.listDataGroup(groupQuery).stream()
            .collect(Collectors.toMap(DataGroupDto::getId, Function.identity()));

        Map<Long, LinkDomain> domainMap = linkDomainManager.listByIds(domainIds).stream()
                .collect(Collectors.toMap(LinkDomain::getId, Function.identity()));

        return PageUtil.to(pageData, (e) -> {
            AccessLogResp resp = accessLogAssembly.toAccessLogResp(e);
            String domain = Optional.ofNullable(domainMap.get(e.getDomainId())).map(LinkDomain::getDomain).orElse("");
            resp.setShortUrl(UrlUtils.removeRepeatSlashOfUrl(domain + "/" + e.getCode()));
            resp.setGroupName(Optional.ofNullable(groupMap.get(e.getGroupId())).map(DataGroupDto::getName).orElse("-"));
            return resp;
        });
    }

    /**
     * 保存 短链访问日志
     *
     * @param entity 新增的记录
     * @return 返回影响行数
     */
    @Override
    public boolean saveAccessLog(AccessLog entity) {
        entity.setAddress(infraApi.ip2Region(entity.getIp()).map(Ip2RegionDto::defaultFormat).orElse("未知"));
        shortLinkService.addAccountCount(entity.getLinkId(), entity.getCode());
    	return this.save(entity);
    }
    
    /**
     * 通过ids删除 短链访问日志
     *
     * @param ids 删除的主键
     * @return 返回影响行数
     */
    @Override
    public boolean deleteAccessLogByIds(List<Long> ids) {
    	return this.removeByIds(ids);
    }
}
